package com.hoow.shakoow.shake.payBilling

import com.android.billingclient.api.*
import com.google.common.collect.ImmutableList
import com.hoow.shakoow.ProjectApplication
import com.hoow.shakoow.base.BaseActivity

class PayBillingManager(val activity: BaseActivity) {

    // 状态回调
    private var mProcessListener: PayBillingProcessListener? = null

    // 日志输出
    private val mLogBuilder: StringBuilder = StringBuilder("")

    companion object {

        fun formatPurchasedCode(responseCode: Int): String {
            when (responseCode) {
                Purchase.PurchaseState.PURCHASED -> {
                    return ("PBL->PurchaseState: $responseCode PURCHASED")
                }
                Purchase.PurchaseState.PENDING -> {
                    return ("PBL->PurchaseState: $responseCode PENDING")
                }
                else -> {
                    return ("PBL->PurchaseState: $responseCode UNSPECIFIED_STATE")
                }
            }
        }

        fun formatErrorCode(responseCode: Int): String {
            when (responseCode) {
                BillingClient.BillingResponseCode.BILLING_UNAVAILABLE -> {
                    return ("PBL->handleError: $responseCode BILLING_UNAVAILABLE")
                }
                BillingClient.BillingResponseCode.SERVICE_TIMEOUT -> {
                    return ("PBL->handleError: $responseCode SERVICE_TIMEOUT")
                }
                BillingClient.BillingResponseCode.FEATURE_NOT_SUPPORTED -> {
                    return ("PBL->handleError: $responseCode FEATURE_NOT_SUPPORTED")
                }
                BillingClient.BillingResponseCode.SERVICE_DISCONNECTED -> {
                    return ("PBL->handleError: $responseCode SERVICE_DISCONNECTED")
                }
                BillingClient.BillingResponseCode.USER_CANCELED -> {
                    return ("PBL->handleError: $responseCode USER_CANCELED")
                }
                BillingClient.BillingResponseCode.SERVICE_UNAVAILABLE -> {
                    return ("PBL->handleError: $responseCode SERVICE_UNAVAILABLE")
                }
                BillingClient.BillingResponseCode.ITEM_UNAVAILABLE -> {
                    return ("PBL->handleError: $responseCode ITEM_UNAVAILABLE")
                }
                BillingClient.BillingResponseCode.DEVELOPER_ERROR -> {
                    return ("PBL->handleError: $responseCode DEVELOPER_ERROR")
                }
                BillingClient.BillingResponseCode.ERROR -> {
                    return ("PBL->handleError: $responseCode ERROR")
                }
                BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED -> {
                    return ("PBL->handleError: $responseCode ITEM_ALREADY_OWNED")
                }
                BillingClient.BillingResponseCode.ITEM_NOT_OWNED -> {
                    return ("PBL->handleError: $responseCode ITEM_NOT_OWNED")
                }
                BillingClient.BillingResponseCode.NETWORK_ERROR -> {
                    return ("PBL->handleError: $responseCode NETWORK_ERROR")
                }
                else -> {
                    return ("PBL->handleError: $responseCode UNKNOW")
                }
            }
        }
    }

    // 保存支付信息
    private fun savePayOrderProcessInfo(pToken: String, pOrderId: String?) {
        printLog("PBL->savePayOrderProcessInfo: token: $pToken, orderId:$pOrderId")

        if (mProcessListener == null) {
            printLog("PBL->savePayOrderProcessInfo: mProcessListener is null")
        }

        if (pToken.isNotBlank()) {
            mProcessListener?.onPayPurchased(pToken, pOrderId ?: "")
        }
    }

    // 保存支付成功
    private fun savePayOrderSuccessInfo(pToken: String, pOrderId: String?) {
        printLog("PBL->savePayOrderSuccessInfo: token: $pToken, orderId:$pOrderId")

        if (mProcessListener == null) {
            printLog("PBL->savePayOrderSuccessInfo: mProcessListener is null")
        }

        if (pToken.isNotBlank()) {
            mProcessListener?.onPayConsumed(pToken, pOrderId ?: "")
        }
    }

    // 1
    private val purchasesUpdatedListener = PurchasesUpdatedListener { billingResult, purchases ->
        // To be implemented in a later section.
        println("billingResult: ${billingResult.toString()}")
        printLog("PBL->onPurchasesUpdated state: ${billingResult.toString()}")

        if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
            for (purchase in purchases) {
                // 处理购买成功的情况
                handlePurchase(purchase)
            }
        } else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
            // 用户取消购买
            handleUserCancelled()
        } else {
            // 处理其他错误情况
            handleError(billingResult.responseCode)
        }

    }

    // 2
    private var billingClient = BillingClient.newBuilder(ProjectApplication.context)
        .setListener(purchasesUpdatedListener)
        .enablePendingPurchases()
        .build()

    // 3-1
    fun startNewPurchased() {
        billingClient.startConnection(
            object : BillingClientStateListener {
                override fun onBillingSetupFinished(billingResult: BillingResult) {
                    printLog("PBL-> startNewPurchased connection state: ${billingResult.toString()}")
                    if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                        // The BillingClient is ready. You can query purchases here.
                        printLog("PBL->connection state: OK")
                        val supportTypeResult =
                            billingClient.isFeatureSupported(BillingClient.FeatureType.PRODUCT_DETAILS)
                        if (supportTypeResult.responseCode == BillingClient.BillingResponseCode.FEATURE_NOT_SUPPORTED) {
                            printLog("PBL->use querySkuDetailsAsync")
                            querySkuDetailsAsync()
                        } else {
                            printLog("PBL->use queryProductDetailsAsync")
                            queryProductDetailsAsync()
                        }
                    } else {
                        printLog("PBL-> startNewPurchased connection state: Error: ${billingResult.toString()}")
                    }
                }

                override fun onBillingServiceDisconnected() {
                    printLog("PBL->startNewPurchased connection state: Disconnected")
                }
            })
    }

    // 3-2
    fun queryPurchaseHistory() {
        billingClient.startConnection(
            object : BillingClientStateListener {
                override fun onBillingSetupFinished(billingResult: BillingResult) {
                    printLog("PBL-> queryPurchaseHistory state: ${billingResult.toString()}")

                    if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                        // The BillingClient is ready. You can query purchases here.
                        printLog("PBL-> queryPurchaseHistory 查询历史购买成功")
                        queryPurchasesInProcess()
                    } else {
                        printLog("PBL->queryPurchaseHistory connection state: Error: ${billingResult.toString()}")
                        printLog("PBL-> queryPurchaseHistory 查询历史购买失败")
                    }
                }

                override fun onBillingServiceDisconnected() {
                    printLog("PBL-> queryPurchaseHistory connection state: Disconnected")
                }
            })
    }

    // 4-new version
    private fun queryProductDetailsAsync() {
        val queryProductDetailsParams =
            QueryProductDetailsParams.newBuilder()
                .setProductList(
                    ImmutableList.of(
                        QueryProductDetailsParams.Product.newBuilder()
                            .setProductId(PayProductUtil.getProUnitId())
                            .setProductType(BillingClient.ProductType.INAPP)
                            .build()
                    )
                )
                .build()

        billingClient.queryProductDetailsAsync(queryProductDetailsParams) { billingResult,
                                                                            productDetailsList ->
            printLog("PBL->queryProductDetailsAsync state: ${billingResult.toString()}")
            if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                if (productDetailsList.isNotEmpty()) {
                    printLog("PBL->queryProductDetailsAsync state: launchBillingFlow")
                    val productDetail = productDetailsList.first()
                    launchProductBillingFlow(productDetail)
                }
            }
        }
    }

    // 4-old version
    private fun querySkuDetailsAsync() {
        val querySkuDetailsParams =
            SkuDetailsParams.newBuilder()
                .setSkusList(mutableListOf(PayProductUtil.getProUnitId()))
                .setType(BillingClient.SkuType.INAPP)
                .build()

        billingClient.querySkuDetailsAsync(querySkuDetailsParams) { billingResult,
                                                                    skuDetailsList ->

            printLog("PBL->querySkuDetailsAsync state: ${billingResult.toString()}")

            if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                // The BillingClient is ready. You can query purchases here.
                skuDetailsList?.let { list ->
                    if (list.isNotEmpty()) {
                        printLog("PBL->querySkuDetailsAsync state: launchSkuBillingFlow")
                        val skuDetail = list.first()
                        launchSkuBillingFlow(skuDetail)
                    } else {
                        printLog("PBL->querySkuDetailsAsync state: no product found")
                    }
                }

                if (skuDetailsList == null) {
                    printLog("PBL->querySkuDetailsAsync state: product is null")
                }
            }
        }
    }

    // 5-new version
    private fun launchProductBillingFlow(productDetails: ProductDetails) {
        // An activity reference from which the billing flow will be launched.
        val productDetailsParamsList = listOf(
            BillingFlowParams.ProductDetailsParams.newBuilder()
                // retrieve a value for "productDetails" by calling queryProductDetailsAsync()
                .setProductDetails(productDetails)
                .build()
        )

        val billingFlowParams = BillingFlowParams.newBuilder()
            .setProductDetailsParamsList(productDetailsParamsList)
            .build()

        // Launch the billing flow
        val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)
        printLog("PBL->launchBillingFlow state: ${billingResult.toString()}")
    }

    // 5-old version
    private fun launchSkuBillingFlow(skuDetails: SkuDetails) {
        // An activity reference from which the billing flow will be launched.
        val billingFlowParams = BillingFlowParams.newBuilder()
            .setSkuDetails(skuDetails)
            .build()

        // Launch the billing flow
        val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)
        printLog("PBL->launchSkuBillingFlow state: ${billingResult.toString()}")
    }

    // 6
//    override fun onPurchasesUpdated(
//        billingResult: BillingResult,
//        purchases: MutableList<Purchase>?
//    ) {
//        println("billingResult: ${billingResult.toString()}")
//        printLog("PBL->onPurchasesUpdated state: ${billingResult.toString()}")
//
//        if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
//            for (purchase in purchases) {
//                // 处理购买成功的情况
//                handlePurchase(purchase)
//            }
//        } else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
//            // 用户取消购买
//            handleUserCancelled()
//        } else {
//            // 处理其他错误情况
//            handleError(billingResult.responseCode)
//        }
//    }

    private fun handleHistoryPurchase(purchase: Purchase) {
        // 处理购买成功的逻辑，例如向用户提供购买的功能或服务
        // 可以通过 purchase 对象获取购买的详细信息

        val pState = purchase.purchaseState
        val pStateFormat = formatPurchasedCode(pState)
        printLog(pStateFormat)

        if (pState == Purchase.PurchaseState.PURCHASED) {
            val pToken = purchase.purchaseToken
            val pOrderId = purchase.orderId

            printLog("PBL->handlePurchase token: $pToken")
            printLog("PBL->handlePurchase orderId: $pOrderId")

            // 保存支付信息
            savePayOrderProcessInfo(pToken, pOrderId)

            // 需要验证
            consumeAsync(purchase)
        }
    }

    private fun handlePurchase(purchase: Purchase) {
        // 处理购买成功的逻辑，例如向用户提供购买的功能或服务
        // 可以通过 purchase 对象获取购买的详细信息

        val pState = purchase.purchaseState
        val pStateFormat = formatPurchasedCode(pState)
        printLog(pStateFormat)

        if (pState == Purchase.PurchaseState.PURCHASED) {
            val pToken = purchase.purchaseToken
            val pOrderId = purchase.orderId

            printLog("PBL->handlePurchase token: $pToken")
            printLog("PBL->handlePurchase orderId: $pOrderId")

            // 保存支付信息
            savePayOrderProcessInfo(pToken, pOrderId)

            // 需要验证
            consumeAsync(purchase)
        }
    }

    private fun handleUserCancelled() {
        // 用户取消购买时的处理逻辑
        println("cancel: handleUserCancelled")
        printLog("PBL->handleUserCancelled")
    }

    private fun handleError(responseCode: Int) {
        // 处理其他错误情况，可以根据 responseCode 提供相应的用户反馈
        println("error: handleError: $responseCode")
        val codeMsg = formatErrorCode(responseCode)
        printLog(codeMsg)
    }

    /**
     * 7
     * 查询进行中的交易
     * 通常在onResume中调用
     */
    fun queryPurchasesInProcess() {
        printLog("PBL->queryPurchasesInProcess")

        // 查询用户的购买历史
        val params = QueryPurchasesParams.newBuilder()
            .setProductType(BillingClient.ProductType.INAPP)
            .build()

        // 开始查询
        billingClient.queryPurchasesAsync(params) { billingResult: BillingResult, purchases: MutableList<Purchase>? ->
            printLog("PBL->queryPurchasesInProcess state: ${billingResult.toString()}")

            // 处理交易
            if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                if (purchases != null) {
                    if (purchases.size > 0) {
                        printLog("PBL->queryPurchasesInProcess 存在待确认的消耗")

                        for (purchase in purchases) {
                            // 处理购买成功的情况
                            handleHistoryPurchase(purchase)
                        }
                    } else {
                        printLog("PBL->queryPurchasesAsync 没有待确认的消耗")
                        printLog("PBL->queryPurchasesAsync 可以调起支付流程")
                        mProcessListener?.onCanPurchaseNow()
                    }
                } else {
                    printLog("PBL->queryPurchasesAsync 没有待确认的消耗")
                    printLog("PBL->queryPurchasesAsync 可以调起支付流程")
                    mProcessListener?.onCanPurchaseNow()
                }
            } else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
                // 用户取消购买
                handleUserCancelled()
                printLog("PBL->queryPurchasesAsync 用户取消购买")
                printLog("PBL->queryPurchasesAsync 可以调起支付流程")
                mProcessListener?.onCanPurchaseNow()

            } else {
                // 处理其他错误情况
                handleError(billingResult.responseCode)

                printLog("PBL->queryPurchasesAsync 其他错误情况")
                printLog("PBL->queryPurchasesAsync 可以调起支付流程")
                mProcessListener?.onCanPurchaseNow()
            }
        }
    }

    // 8 消耗商品
    private fun consumeAsync(purchase: Purchase) {
        printLog("PBL->consumeAsync: start")
        printLog("PBL->consumeAsync: 开始确认消耗")

        val pToken = purchase.purchaseToken
        val pOrderId = purchase.orderId

        val consumeParams = ConsumeParams.newBuilder()
            .setPurchaseToken(purchase.purchaseToken)
            .build()
        val listener =
            ConsumeResponseListener { billingResult: BillingResult, purchaseToken: String ->
                printLog("PBL->consumeAsync state: ${billingResult.toString()}")
                if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                    printLog("PBL->consumeAsync state: 消耗成功")

                    // 保存支付信息
                    savePayOrderSuccessInfo(pToken, pOrderId ?: "")
                } else {
                    printLog("PBL->consumeAsync state: 消耗失败")
                }
            }
        billingClient.consumeAsync(consumeParams, listener)
    }

    /**
     * 设置状态监听
     */
    fun setPayBillingListener(listener: PayBillingProcessListener) {
        mProcessListener = listener
    }

    /**
     * 输出日志
     */
    private fun printLog(text: String) {
        if (text.isNotBlank()) {
            mLogBuilder.append("\n\n")
            mLogBuilder.append(text)

            // 日志回调
            mProcessListener?.onPrintLog(text)
        }
    }
}